﻿Imports EIBWatcherNet.Core.EIB.Bus
Imports EIBWatcherNet.Core.EIB.Bus.Addressing
Imports EIBWatcherNet.Core.EIBData
Imports EIBWatcherNet.Core.EIB.Managers
Imports EIBWatcherNet.Core.EIBData.EventArgs

Namespace EIB
    Public NotInheritable Class BusManager
        Private WithEvents _busAccess As IEIBBusAccessModule = Nothing
        Private _isSimulation As Boolean = Nothing

        Private _addressValues As New EIBGroupAddressValueManager
        Private _addressTypes As New EIBGroupAddressDataTypeManager


        Public Event LogBusData(reason As EIBBusAccessLogReason, message As String, data As Byte())
        Public Event BusDataReceived As EventHandler(Of EIBBusDataUpdatedEventArgs)


        Sub New(accessModule As IEIBBusAccessModule)
            If accessModule Is Nothing Then Throw New Exceptions.EIBException("")

            _busAccess = accessModule
        End Sub

        Sub New(port As ConnectionPort)
            Dim accessModuleType As Type = port.GetAccessModuleType

            If accessModuleType Is Nothing Then Throw New NotImplementedException

            _busAccess = Activator.CreateInstance(accessModuleType)
        End Sub


        Public Function CanOpenPort(port As ConnectionPort) As Boolean
            Return _busAccess.GetType = port.GetAccessModuleType
        End Function


#Region "Managers Handling"
        Public Sub ClearAddressValues()
            _addressValues.Clear()
        End Sub

        Public Sub ClearTypeValues()
            _addressTypes.Clear()
        End Sub

        Public Sub SetAddressType(address As EIBGroupAddress, type As EIBDataTypeManger)
            _addressTypes.SetValue(address, type)
        End Sub

        Public Sub SetAddressType(address As EIBGroupAddress, type As EIBData.EIS.EIBDataEIS_Base)
            _addressTypes.SetValue(address, type)
        End Sub

        Public Sub SetAddressType(address As EIBGroupAddress, type As EIBData.DPT.EIBDataDPT_Base)
            _addressTypes.SetValue(address, type)
        End Sub
#End Region

#Region "Public Interface"
        Public Function Open(ParamArray params() As Object) As Boolean
            Return _busAccess.OpenConnection(params)
        End Function

        Public Sub Close()
            _busAccess.CloseConnection()
        End Sub

        Public ReadOnly Property IsConnected As Boolean
            Get
                Return _busAccess.IsConnected
            End Get
        End Property

        Public ReadOnly Property IsSimualtion As Boolean
            Get
                Return _isSimulation
            End Get
        End Property

        Public Sub ReadGroupAddress(address As EIBGroupAddress)
            If _addressValues.Contains(address) Then
                'read from memory
                RaiseEvent LogBusData(EIBBusAccessLogReason.Information, String.Format("Data read from memory: address: {0} value: {1}", address.ToString, EIB.Helper.ConvertByteArrayToHexString(_addressValues.GetValue(address).Data)), Nothing)
                RaiseEvent BusDataReceived(Me, New EIBBusDataUpdatedEventArgs(EIBBusDataUpdateReasons.Read, address, _addressValues.GetValue(address)))
            Else
                'read from bus
                ReadGroupAddressInternal(address)
            End If
        End Sub

        Public Sub ForceReadGroupAddress(address As EIBGroupAddress)
            ReadGroupAddressInternal(address)
        End Sub

        Public Sub ReadGroupAddressRange(addresses As EIBGroupAddressListManager)
            For Each address As EIBGroupAddress In addresses.GetValues
                ReadGroupAddress(address)
            Next
        End Sub

        Public Sub RespondGroupAddress(address As EIBGroupAddress, value As Byte())
            RespondGroupAddressInternal(address, value)
        End Sub

        Public Sub RespondGroupAddress(address As EIBGroupAddress, value As EIBData.EIS.EIBDataEIS_Base)
            RespondGroupAddressInternal(address, value.ToByte)
        End Sub

        Public Sub RespondGroupAddress(address As EIBGroupAddress, value As EIBData.DPT.EIBDataDPT_Base)
            RespondGroupAddressInternal(address, value.ToByte)
        End Sub

        Public Sub RespondGroupAddress(address As EIBGroupAddress, value As EIBDataContainer)
            RespondGroupAddressInternal(address, value.Data)
        End Sub

        Public Sub WriteGroupAddress(address As EIBGroupAddress, value As Byte())
            WriteGroupAddressInternal(address, value)
        End Sub

        Public Sub WriteGroupAddress(address As EIBGroupAddress, value As EIBData.EIS.EIBDataEIS_Base)
            WriteGroupAddressInternal(address, value.ToByte)
        End Sub

        Public Sub WriteGroupAddress(address As EIBGroupAddress, value As EIBData.DPT.EIBDataDPT_Base)
            WriteGroupAddressInternal(address, value.ToByte)
        End Sub

        Public Sub WriteGroupAddress(address As EIBGroupAddress, value As EIBDataContainer)
            WriteGroupAddressInternal(address, value.Data)
        End Sub

        Public Function ResetBCU() As Boolean
            Return _busAccess.ResetBCU
        End Function

        Public Sub GetLinkStatus()
            _busAccess.GetLinkStatus()
        End Sub
#End Region

#Region "Bus Access"
        Private Sub ReadGroupAddressInternal(address As EIBGroupAddress)
            _busAccess.ReadBusData(address)
        End Sub

        Private Sub RespondGroupAddressInternal(address As EIBGroupAddress, value As Byte())
            _busAccess.RespondBusData(address, value)
        End Sub

        Private Sub WriteGroupAddressInternal(address As EIBGroupAddress, value As Byte())
            _busAccess.WriteBusData(address, value)

            'eigner "Empfang"
            Dim container As New EIBDataContainer(value)

            If _addressTypes.Contains(address) Then
                container.TryDecodeAs(_addressTypes.GetValue(address))
            End If

            _addressValues.SetValue(address, container)
            RaiseEvent BusDataReceived(Me, New EIBBusDataUpdatedEventArgs(EIBBusDataUpdateReasons.Write, address, container))
        End Sub

        Private Sub _busAccess_LogBusData(reason As Bus.EIBBusAccessLogReason, message As String, data() As Byte) Handles _busAccess.LogBusData
            RaiseEvent LogBusData(reason, message, data)
        End Sub

        Private Sub _busAccess_ReceiveBusData(address As Bus.Addressing.EIBAddress, value() As Byte) Handles _busAccess.ReceiveBusData
            If TypeOf address Is EIBGroupAddress Then
                Dim container As New EIBDataContainer(value)

                If _addressTypes.Contains(address) Then
                    container.TryDecodeAs(_addressTypes.GetValue(address))
                End If

                _addressValues.SetValue(address, container)
                RaiseEvent BusDataReceived(Me, New EIBBusDataUpdatedEventArgs(EIBBusDataUpdateReasons.BusReceived, address, container))
            End If
        End Sub
#End Region
    End Class
End Namespace